/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.uc.manager.impl;

import com.xy.biz.uc.dao.ResourceDao;
import com.xy.biz.uc.dao.RoleDao;
import com.xy.biz.uc.dao.RoleResourceRelDao;
import com.xy.biz.uc.domain.bo.ResourceBO;
import com.xy.biz.uc.domain.bo.RoleBO;
import com.xy.biz.uc.domain.converter.ResourceConverter;
import com.xy.biz.uc.domain.converter.RoleConverter;
import com.xy.biz.uc.domain.po.RolePO;
import com.xy.biz.uc.domain.po.RoleResourceRelPO;
import com.xy.biz.uc.domain.query.RoleIdQuery;
import com.xy.biz.uc.domain.query.RoleQuery;
import com.xy.biz.uc.manager.RoleManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 
 * 
 * @author zsp
 * @date 2020-8-19
 */
@Service
public class RoleManagerImpl implements RoleManager {

	@Autowired
	private RoleDao roleDao;
	@Autowired
	private RoleResourceRelDao roleResourceRelDao;
	@Autowired
	private ResourceDao resourceDao;

	@Transactional
	@Override
	public int saveRole(RoleBO roleBO) {
		RolePO rolePO = RoleConverter.toPO(roleBO);
		int affectedRows = roleDao.saveRole(rolePO);
		if(affectedRows > 0) {
			List<Long> resourceIdList = roleBO.getResourceIdList();
			if (!CollectionUtils.isEmpty(resourceIdList)) {
				List<RoleResourceRelPO> roleResourceRelPOList
						= resourceIdList.stream().map(e -> new RoleResourceRelPO(rolePO.getRoleId(), e)).collect(Collectors.toList());
				roleResourceRelDao.saveAllRoleResourceRel(roleResourceRelPOList);
			}
		}
		return affectedRows;
	}

	@Transactional
	@Override
	public int updateRole(RoleBO roleBO) {
		int affectedRows = roleDao.updateRole(RoleConverter.toPO(roleBO));
		if(affectedRows > 0) {
			roleResourceRelDao.deleteRoleResourceRelByRoleId(roleBO.getRoleId());
			List<Long> resourceIdList = roleBO.getResourceIdList();
			if (!CollectionUtils.isEmpty(resourceIdList)) {
				List<RoleResourceRelPO> roleResourceRelPOList
						= resourceIdList.stream().map(e -> new RoleResourceRelPO(roleBO.getRoleId(), e)).collect(Collectors.toList());
				roleResourceRelDao.saveAllRoleResourceRel(roleResourceRelPOList);
			}
		}
		return affectedRows;
	}

	@Transactional
	@Override
	public int deleteRole(Long roleId) {
		int affectedRows =  roleDao.deleteRole(roleId);
		if(affectedRows > 0) {
			roleResourceRelDao.deleteRoleResourceRelByRoleId(roleId);
		}
		return affectedRows;
	}

	@Override
	public boolean isRoleCodeExists(String roleCode) {
		return roleDao.isRoleCodeExists(roleCode);
	}

	@Override
	public RoleBO getRole(RoleIdQuery roleIdQuery) {
		Long roleId = roleIdQuery.firstRoleId();
		RoleBO roleBO = RoleConverter.fromPO(roleDao.getRole(roleId));
		if(roleBO != null && roleIdQuery.isWithResource()) {
			Map<Long, List<ResourceBO>> map = findResourceByRoleId(Arrays.asList(roleId));
			roleBO.setResourceBOList(map.get(roleId));
		}
		return roleBO;
	}

	/**
	 * 查找一个
	 *
	 * @param roleCode
	 * @return
	 */
	@Override
	public RoleBO getRoleByCode(String roleCode) {
		RolePO rolePO = roleDao.getRoleByCode(roleCode);
		return RoleConverter.fromPO(rolePO);
	}

	@Override
	public List<RoleBO> listRoleById(RoleIdQuery roleIdQuery) {
		List<RoleBO> roleBOList = RoleConverter.fromPO(roleDao.listRoleById(roleIdQuery.getRoleIdList()));
		if(!CollectionUtils.isEmpty(roleBOList) && roleIdQuery.isWithResource()) {
			Map<Long, List<ResourceBO>> map = findResourceByRoleId(roleIdQuery.getRoleIdList());
			for(RoleBO roleBO : roleBOList) {
				roleBO.setResourceBOList(map.get(roleBO.getRoleId()));
			}
		}
		return roleBOList;
	}

	@Override
	public List<RoleBO> listRoleByCode(Collection<String> roleCodeCollection) {
		List<RoleBO> roleBOList = RoleConverter.fromPO(roleDao.listRoleByCode(roleCodeCollection));
		return roleBOList;
	}

	private Map<Long, List<ResourceBO>> findResourceByRoleId(Collection<Long> roleIdCollection) {
		List<RoleResourceRelPO> roleResourceRelPOList = roleResourceRelDao.listRoleResourceRelByRoleId(roleIdCollection);
		if(!CollectionUtils.isEmpty(roleResourceRelPOList)) {
			Map<Long, List<RoleResourceRelPO>> resourceGroup = roleResourceRelPOList.stream().collect(Collectors.groupingBy(RoleResourceRelPO::getResourceId));
			List<ResourceBO> resourceBOList = ResourceConverter.fromPO(resourceDao.listResourceById(resourceGroup.keySet()));
			if(!CollectionUtils.isEmpty(resourceBOList)) {
				Map<Long, List<ResourceBO>> roleMap = new HashMap<>();
				for(ResourceBO resourceBO : resourceBOList) {
					List<RoleResourceRelPO> group = resourceGroup.get(resourceBO.getResourceId());
					if(!CollectionUtils.isEmpty(group)) {
						for (RoleResourceRelPO roleResourceRelPO : group) {
							List<ResourceBO> list = roleMap.computeIfAbsent(roleResourceRelPO.getRoleId(), e -> new ArrayList<>());
							list.add(resourceBO);
						}
					}
				}
			}
		}
		return Collections.emptyMap();
	}
	
	@Override
	public List<RoleBO> listRole(RoleQuery query) {
		return RoleConverter.fromPO(roleDao.listRole(query));
	}
	
	@Override
	public int countRole(RoleQuery query) {
		return roleDao.countRole(query);
	}

	@Override
	public List<Long> listResourceIdByRoleId(Long roleId) {
		List<RoleResourceRelPO> roleResourceRelPOList = roleResourceRelDao.listRoleResourceRelByRoleId(Arrays.asList(roleId));
		if(!CollectionUtils.isEmpty(roleResourceRelPOList)) {
			return roleResourceRelPOList.stream().map(RoleResourceRelPO::getResourceId).collect(Collectors.toList());
		}
		return Collections.emptyList();
	}

}
